package com.fnzx.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fnzx.common.enums.UserTypeEnum;
import com.fnzx.common.exception.MailExistException;
import com.fnzx.common.exception.PhoneExistException;
import com.fnzx.dao.UserDao;
import com.fnzx.entity.*;
import com.fnzx.entity.vo.UserInfoVo;
import com.fnzx.service.*;
import com.fnzx.util.PageUtils;
import com.fnzx.util.Query;
import com.fnzx.util.common.Md5Util;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import static com.fnzx.common.constant.UsernamePrefixAndKeyConstant.ENTERPRISE_KEY;
import static com.fnzx.common.constant.UsernamePrefixAndKeyConstant.ENTERPRISE_PREFIX;


@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
    @Autowired
    CooperativeUserService cooperativeUserService;

    @Autowired
    PersonalUserService personalUserService;

    @Autowired
    EnterpriseUserService enterpriseUserService;

    @Autowired
    CooperativePersonalRelationService relationService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    public PageUtils listAdmin(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>().eq("user_type",9)
        );
        return new PageUtils(page);
    }

    @Override
    public PageUtils getAllUserInfoPage(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>().orderByAsc("user_type")
        );
        List<UserEntity> records = page.getRecords();
        List<UserInfoVo> userInfoVoList = records.stream().map(record -> {
            return getUserInfoById(record.getId());
        }).collect(Collectors.toList());
        PageUtils pageUtils = new PageUtils(page);
        pageUtils.setList(userInfoVoList);
        return pageUtils;
    }

    @Override
    public List<UserInfoVo> getAllUserInfo(Integer type) {
        List<UserEntity> records = this.list(new QueryWrapper<UserEntity>().eq("user_type",type));
        List<UserInfoVo> userInfoVoList = records.stream().map(record -> {
            return getUserInfoById(record.getId());
        }).collect(Collectors.toList());
        return userInfoVoList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserInfoVo getUserInfoById(Long id) {
        UserEntity user = this.getById(id);
        if (user!=null){
            Integer type = user.getUserType();
            UserInfoVo userInfoVo = new UserInfoVo();
            BeanUtils.copyProperties(user,userInfoVo);
            Object byId=null;
            if (type.equals(UserTypeEnum.ENTERPRISE_TYPE)){
                byId = enterpriseUserService.getById(id);
            }else if (type.equals(UserTypeEnum.COOPERATIVE_TYPE)){
                byId = cooperativeUserService.getById(id);
            }else if (type.equals(UserTypeEnum.PERSONAL_TYPE)){
                byId = personalUserService.getById(id);
            }
            String s = JSON.toJSONString(byId);
            userInfoVo.setUserInfo(JSON.parseObject(s, HashMap.class));
            return userInfoVo;
        }
        return null;
    }

    @Override
    public UserEntity login(HashMap<String, String> map) {
        //这里的用户名可以是 电话号码 或者 邮箱
        String username = map.get("username");
        String password = Md5Util.md5(map.get("password"));
        UserEntity user=this.baseMapper.login(username,password);
        return user;
    }

    @Override
    public UserEntity adminLogin(HashMap<String, String> map) {
        String username = map.get("username");
        String password = Md5Util.md5(map.get("password"));
        UserEntity user = this.getOne(new QueryWrapper<UserEntity>()
                .eq("username", username)
                .eq("password", password)
                .eq("user_type",UserTypeEnum.SUPER_ADMIN_TYPE));
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void rigister(UserEntity userEntity) {
        //检查电话号码和邮箱是否重复
        checkPhoneUnique(userEntity.getTelephone());
        checkMailUnique(userEntity.getEmail());

        String password = userEntity.getPassword();
        Integer type=userEntity.getUserType();

        //todo：给上用户特殊的ID，见接口注释，因为0的个数不定，这里我暂定数字只有四位，写下以下的常数变量
        if (type.equals(UserTypeEnum.ENTERPRISE_TYPE)){
            String num = redisTemplate.opsForValue().get(ENTERPRISE_KEY);
            StringBuilder sb = new StringBuilder(ENTERPRISE_PREFIX);
            while(sb.length()<(5-num.length())){
                sb.append(0);
            }
            String username=sb+num;
            userEntity.setUsername(username);
            redisTemplate.opsForValue().increment(ENTERPRISE_KEY);
        }else if (type.equals(UserTypeEnum.PERSONAL_TYPE)){
            String num = redisTemplate.opsForValue().get(ENTERPRISE_KEY);
            StringBuilder sb = new StringBuilder(ENTERPRISE_PREFIX);
            while(sb.length()<(6- Objects.requireNonNull(num).length())){
                sb.append(0);
            }
            String username=sb+num;
            userEntity.setUsername(username);
            redisTemplate.opsForValue().increment(ENTERPRISE_KEY);
        }

        userEntity.setPassword(Md5Util.md5(password));
        this.save(userEntity);
        Long id = userEntity.getId();
        if (type.equals(UserTypeEnum.ENTERPRISE_TYPE)){
            EnterpriseUserEntity entity = new EnterpriseUserEntity();
            entity.setId(id);
            enterpriseUserService.save(entity);
        }else if (type.equals(UserTypeEnum.COOPERATIVE_TYPE)){
            CooperativeUserEntity entity = new CooperativeUserEntity();
            entity.setId(id);
            cooperativeUserService.save(entity);
        }else if (type.equals(UserTypeEnum.PERSONAL_TYPE)){
            PersonalUserEntity entity = new PersonalUserEntity();
            entity.setId(id);
            personalUserService.save(entity);
        }
    }

    @Override
    public void prohibit(Long id,Integer status) {
        this.baseMapper.prohibit(id,status);
    }

    @Override
    public Integer queryStatusById(Long id) {
        return this.baseMapper.queryStatusById(id);
    }

    @Override
    public void delete(List<Long> ids) {
        this.removeByIds(ids);
        personalUserService.removeByIds(ids);
        enterpriseUserService.removeByIds(ids);
        cooperativeUserService.removeByIds(ids);
        relationService.remove(
            new QueryWrapper<CooperativePersonalRelationEntity>()
                    .in("personal_id",ids)
                    .or()
                    .in("cooperative_id",ids)
        );
    }

    /**
     * 检查电话号码是否已经存在
     * @param phone
     * @throws PhoneExistException
     */
    public void checkPhoneUnique(String phone) throws PhoneExistException{
        if (ObjectUtils.isEmpty(phone)){
            throw new PhoneExistException("电话号码为空,请填写");
        }
        int count = this.count(new QueryWrapper<UserEntity>().eq("telephone", phone));
        if (count>0){
            throw new PhoneExistException();
        }
    }

    /**
     * 检查邮箱是否已经存在
     * @param mail
     * @throws MailExistException
     */
    public void checkMailUnique(String mail) throws MailExistException {
        if (ObjectUtils.isEmpty(mail)){
            throw new PhoneExistException("邮箱为空");
        }
        int count = this.count(new QueryWrapper<UserEntity>().eq("email", mail));
        if (count>0){
            throw new MailExistException();
        }
    }
}